package com.zmn.plat.admin.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.session.UnknownSessionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.servlet.ModelAndView;

import com.zmn.common.constant.StatusConsts;
import com.zmn.common.dto.ResultDTO;

/**
 * 全局控制器异常处理器；处理控制器抛出的未处理异常，包含全局异常处理、公用异常处理。
 * <p>
 * <p>
 * 异常处理顺序： 1. 响应内容类型非空：若为JSON则返回JSON错误，否则返回ERROR PAGE 2. 请求内容类型非空：若为JSON则返回JSON错误，否则返回ERROR PAGE 3. 返回ERROR PAGE
 * </p>
 *
 * @author duanzuocai
 * @version v1.0
 * @类说明：异常返回格式统一管理
 * @since 2018/10/25 14:26
 */
@ControllerAdvice
public class GlobalExceptionHandler {

    private final static Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    public static String JSON = "application/json";
    public static String JSONP = "application/jsonp";

    @Value("${web.error.page:none}")
    private String webErrorJson;

    /**
     * 全局异常处理
     *
     * @param request
     * @param response
     * @param e
     * @return
     */
    @ExceptionHandler(Throwable.class)
    public Object errorHandler(HttpServletRequest request, HttpServletResponse response, Throwable e) {

        logger.error(e.getMessage(), e);

        String message = StringUtils.substring(e.getMessage(), 0, 200);

        if ("json".equalsIgnoreCase(webErrorJson)) {
            return errorJson(message);
        }

        String reqContentType = request.getHeader("Content-Type");
        String resContentType = response.getHeader("Content-Type");

        // 响应内容类
        if (StringUtils.isNotEmpty(resContentType)) {
            if (JSON.equalsIgnoreCase(resContentType) || JSONP.equalsIgnoreCase(resContentType)) {
                // JSON
                return errorJson(message);
            } else {
                // PAGE
                return errorPage(message);
            }
        }

        // 请求内容类型
        if (StringUtils.isNotEmpty(reqContentType)) {
            if (JSON.equalsIgnoreCase(reqContentType) || JSONP.equalsIgnoreCase(reqContentType)) {
                // JSON
                return errorJson(message);
            } else {
                // PAGE
                return errorPage(message);
            }
        }

        return errorPage(message);

    }

    /**
     * Shiro验证失败，抛出UnauthorizedException异常
     *
     * @param request
     * @param e
     * @return
     */
    @ExceptionHandler({UnauthorizedException.class})
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public ModelAndView processUnauthenticatedException(NativeWebRequest request, UnauthorizedException e) {
        return new ModelAndView("redirect:/untitled.action");
    }

    /**
     *
     * @param request
     * @param e
     * @return
     */
    @ExceptionHandler({UnknownSessionException.class})
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public ModelAndView processUnknownSessionException(NativeWebRequest request, UnauthorizedException e) {
        return new ModelAndView("redirect:/login.action");
    }

    /**
     * @param message
     * @return 错误页面
     */
    @ResponseStatus(HttpStatus.SERVICE_UNAVAILABLE)
    public static ModelAndView errorPage(String message) {
        return new ModelAndView("error/error", "message", message);
    }

    /**
     * @param message
     * @return 错误JSON包装实体
     */
    public static ResultDTO errorJson(String message) {
        return new ResultDTO(StatusConsts.STATUS_ERROR, "ERROR", false, message);
    }

}